P3338 [ZJOI2014]力
题解
题意
给出n个数q1,q2,…,qn定义
Fj=i=1∑j−1(i−j)2qi×qj−i=j+1∑n(i−j)2qi×qjEi=qiFi
对于1≤i≤n, 求Ei的值。
1≤n≤105
解法
首先这个题的数据范围有很大的问题, 原题目中给出的数据范围为0<qi<109, 但是数据中存在qi=0的情况, 所以需要在计算时先将qi消去,(很让人不爽)。
现在要求计算的就是
Fi=j=1∑i−1(i−j)2qj−i=j+1∑n(i−j)2qj
首先考虑拆开计算,设为Fi=Ai−Bi, Ai=∑j=1j−1(i−j)2qj,观察可知,是一个卷积的形式,可以变为
Ai=j+k=i∑qj×k21
然后用FFT就可以计算出A了,然后考虑B的形式和A的一样, 可以直接将qi,reverse
一下,然后计算出B即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| #include <bits/stdc++.h>
using namespace std;
const int N =4e5 + 10; const double pi = acos(-1.0);
struct Complex { double x, y; Complex(double a = 0, double b = 0) : x(a), y(b) {} friend Complex operator + (Complex a, Complex b) {return Complex(a.x + b.x, a.y + b.y);} friend Complex operator - (Complex a, Complex b) {return Complex(a.x - b.x, a.y - b.y);} friend Complex operator * (Complex a, Complex b) {return Complex(a.x * b.x - a.y * b.y, a.y * b.x + b.y * a.x);} };
int n;
double q[N], a[N], b[N];
Complex F[N], G[N];
int rev[N], len = 1;
void FFT(Complex *a, int len, int type) { for(int i = 0; i < len; i++) if(i < rev[i])swap(a[i], a[rev[i]]); for(int k = 1; k < len; k <<= 1) { Complex x(cos(pi / k), type * sin(pi / k)); for(int i = 0; i < len; i += k << 1) { Complex w(1, 0); for(int j = 0; j < k; j++) { Complex y = a[i + j]; Complex z = w * a[i + j + k]; a[i + j] = y + z; a[i + j + k] = y - z; w = w * x; } } } if(type == -1) for(int i = 0; i < len; i++) a[i].x /= len; }
void init() { memset(F, 0, sizeof(F)); memset(G, 0, sizeof(G)); }
void Get() { for(int i = 1; i <= n; i++) F[i].x = q[i]; for(int i = 1; i <= n; i++) G[i].x = 1.0 / i / i; FFT(F, len, 1), FFT(G, len, 1); for(int i = 0; i <= len; i++) F[i] = F[i] * G[i]; FFT(F, len, -1); }
int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%lf", &q[i]); int cnt = 0; while(len <= (n << 1))len <<= 1, cnt++; for(int i = 0; i <= len; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (cnt - 1)); init(); Get(); for(int i = 1; i <= n; i++) a[i] = F[i].x; reverse(q + 1, q + n + 1); init(); Get(); for(int i = 1; i <= n; i++) b[i] = F[i].x; reverse(q + 1, q + n + 1); for(int i = 1; i <= n; i++) printf("%.8lf\n", a[i] - b[n - i + 1]); return 0; }
|